import base64
import json
import logging
import os
import shutil
import tkinter as tk
from datetime import datetime
from tkinter import filedialog, ttk, messagebox
from resource import FILE_ICON_BASE64

# 检查并创建日志目录
if not os.path.exists("logs"):
    os.mkdir("logs")
img_data = base64.b64decode(FILE_ICON_BASE64)
with open("Logo.ico", "wb") as file:
    file.write(img_data)
# 配置日志记录器，设置日志级别为 DEBUG，并将日志输出到文件和控制台
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(f"logs/{datetime.now().strftime('%Y-%m-%d')}.log", encoding="utf-8"),
        logging.StreamHandler()
    ]
)

# 定义默认的 Minecraft 索引路径和资源目录
DEFAULT_MINECRAFT_INDEX_PATH = r"C:/Users/Administrator/AppData/Roaming/.minecraft"
DEFAULT_RESOURCE_INDEX_DIR = "/assets/indexes"
DEFAULT_RESOURCE_DIR = "/assets/objects"
resource_file = DEFAULT_MINECRAFT_INDEX_PATH + DEFAULT_RESOURCE_DIR

# 存储解码后的数据和锁定字典
datas = []
lock_dict = dict()


def do_decode(json_file_path):
    # 解码 JSON 文件，提取特定的资源文件路径
    global datas, lock_dict
    sounds = []
    lock_dict_copy = {}
    logging.info(f"正在解码文件: {json_file_path}")
    try:
        with open(json_file_path, "r") as file:
            content = file.read()
            data = json.loads(content).get("objects", {})
            logging.debug(f"一次解码后的数据: {data}")
    except json.JSONDecodeError as e:
        logging.error(f"JSON 解码错误: {e}")
    sounds = list()
    for i in data.keys():
        split_i = i.split("/")
        if len(split_i) <= 2:
            continue
        if split_i[1] == "sounds" and split_i[2] == "music":
            sounds.append(split_i[-1])
            lock_dict_copy[split_i[-1]] = data[i]["hash"]
    logging.debug(f"二次解码后的目标数据：{sounds}")
    logging.debug(f"绑定表：{lock_dict_copy}")
    datas = sounds
    lock_dict = lock_dict_copy


def print_checkbox_status():
    # 打印并保存复选框的状态
    logging.info("按钮点击 - 复选框状态:")
    lists = list()
    for i, var in enumerate(vars):
        logging.info(f"复选框{datas[i]}: {var.get()}")
        if var.get():
            lists.append(datas[i])
    save_checkbox_status(lists)


def save_checkbox_status(lists):
    # 保存选中的资源文件到指定文件夹
    folder_path = filedialog.askdirectory(initialdir="C:/")
    success = True
    if folder_path:
        logging.info(f"文件将保存到文件夹: {folder_path}")
        for i in lists:
            logging.info(f"正在解码文件: {i}")
            tries = 0
            while tries < 3:
                try:
                    shutil.copy(resource_file + "/" + lock_dict[i][:2] + "/" + lock_dict[i], folder_path + "/" + i)
                except Exception as e:
                    tries += 1
                    logging.error(f"解码文件 {i} 失败，尝试重新解码，尝试次数：{tries}")
                    logging.exception(e)
                    continue
                else:
                    logging.info(f"解码文件 {i} 成功")
                    break
            else:
                success = False
                tk.messagebox.showerror("错误", f"解码文件 {i} 失败，请检查目标文件夹是否无权写入。")
        if success:
            tk.messagebox.showinfo("成功", "解码完成。")
        else:
            tk.messagebox.showinfo("不完全成功", "解码部分完成，但存在解码失败的文件。")
    else:
        logging.info("用户取消了文件夹选择。")


def select_json_file_and_decode(index_path=DEFAULT_MINECRAFT_INDEX_PATH, has_chose=False):
    # 选择并解码 JSON 文件
    global resource_file
    if not (os.path.exists(index_path + DEFAULT_RESOURCE_INDEX_DIR) and os.path.exists(
            index_path + DEFAULT_RESOURCE_DIR)):
        def show_error_popup():
            messagebox.showerror("错误",
                                 f"在 {index_path} 处发生错误：\n.minecraft 文件无效。\n请手动选择")
            select_minecraft_folder()  # 调用选择文件夹函数

        root.after(2500, show_error_popup)  # 2500 毫秒（2.5 秒）后显示错误弹窗
        logging.error(f"默认的 .minecraft 文件无效: {index_path}")
        return
    elif has_chose:
        logging.info("用户选择了 .minecraft 文件夹")
        resource_file = index_path + DEFAULT_RESOURCE_DIR
    else:
        logging.info(f"{index_path}{DEFAULT_RESOURCE_INDEX_DIR} 处存在文件，直接打开默认目录")
        select_minecraft_folder(index_path + DEFAULT_RESOURCE_INDEX_DIR + "/../../")
        return

    json_files = [f for f in os.listdir(index_path + DEFAULT_RESOURCE_INDEX_DIR) if f.endswith('.json')]
    if not json_files:
        messagebox.showerror("错误", f"在 {index_path}{DEFAULT_RESOURCE_INDEX_DIR} 处没有找到 .json 文件，"
                                     "尝试重新选择.Minecraft文件")
        logging.error(f"在 {index_path}{DEFAULT_RESOURCE_INDEX_DIR} 处没有找到 .json 文件")
        select_minecraft_folder()
        return

    # 创建自定义文件选择窗口
    file_select_window = tk.Toplevel(root)
    file_select_window.title("请选择资源版本")
    file_select_window.geometry("400x400")
    file_select_window.iconbitmap('Logo.ico')

    # 当窗口关闭时，执行 on_close 函数
    file_select_window.protocol("WM_DELETE_WINDOW", lambda: on_close(file_select_window))

    # 创建一个 Listbox 来显示 .json 文件
    listbox = tk.Listbox(file_select_window, width=50, height=15)
    listbox.pack(pady=20)

    # 将 .json 文件名（去掉 .json 后缀）添加到 Listbox
    for file in json_files:
        listbox.insert(tk.END, file[:-5])  # 去掉 .json 后缀

    # 创建一个按钮来选择文件
    def on_select():
        selected_index = listbox.curselection()
        if selected_index:
            selected_file = json_files[selected_index[0]]
            json_file_path = os.path.join(index_path + DEFAULT_RESOURCE_INDEX_DIR, selected_file)
            file_select_window.destroy()
            start_loading()
            # 调用 do_decode 函数
            do_decode(json_file_path)
        else:
            messagebox.showinfo("信息", "请选择一个文件。")
            logging.info("用户没有选择文件。")

    select_button = tk.Button(file_select_window, text="就这个版本了", command=on_select)
    select_button.pack()


def on_close(window):
    window.destroy()
    messagebox.showinfo("信息", "用户取消资源版本选择。程序将退出。")
    root.quit()
    logging.info("用户取消资源版本选择。程序将退出。")


def start_loading():
    # 创建加载条窗口
    loading_window = tk.Toplevel(root)
    loading_window.title("加载中...")
    loading_window.geometry("300x100")
    loading_window.iconbitmap('Logo.ico')  # 设置加载窗口图标

    # 创建进度条
    progress = ttk.Progressbar(loading_window, orient="horizontal", length=280, mode="determinate")
    progress.pack(pady=20)

    # 更新进度条
    def update_progress(value):
        if not loading_window.winfo_exists():
            progress.destroy()
            messagebox.showinfo("信息", "用户取消加载。程序将退出。")
            root.quit()
            logging.info("用户取消加载。程序将退出。")
        elif value <= 100:
            progress['value'] = value
            loading_window.update_idletasks()
            root.after(50, update_progress, value + 1)  # 每 10 毫秒更新一次进度
        else:
            # 加载完成后关闭加载条窗口并显示主窗口
            loading_window.destroy()
            show_main_window()
            logging.info("加载完成。")

    # 启动进度条更新
    update_progress(0)


def select_minecraft_folder(init_dir=None):
    # 手动选择 Minecraft 文件夹
    folder_path = filedialog.askdirectory(title="选择 .minecraft 文件夹", initialdir=init_dir)
    if not folder_path:
        # 用户点击了取消
        root.destroy()
        messagebox.showinfo("信息", "用户取消了文件夹选择。程序将退出。")
        root.quit()
        logging.info("用户取消了文件夹选择。程序将退出。")
        return
    select_json_file_and_decode(folder_path, has_chose=True)  # 重新启动加载过程
    logging.info(f"用户选择了文件夹: {folder_path}")


# 定义全选操作的函数
def toggle_all_checkboxes():
    global all_selected
    all_selected = not all_selected
    for var in vars:
        var.set(all_selected)


# 定义重新选择的函数
def re_choose():
    global root
    root.destroy()  # 损毁主窗口
    root.quit()  # 退出主窗口
    # 重建
    root = tk.Tk()
    root.title("选择要导出的文件")
    root.withdraw()  # 隐藏主窗口
    root.iconbitmap('Logo.ico')  # 设置主窗口图标
    select_json_file_and_decode(has_chose=False)
    root.mainloop()


# 在 show_main_window 函数中添加全选按钮
def show_main_window():
    # 隐藏加载条窗口
    root.deiconify()

    # 创建变量来存储复选框的状态
    global vars, checkboxes, all_selected
    vars = [tk.BooleanVar() for _ in datas]
    all_selected = False  # 初始化全选状态为未选中

    # 创建一个 Canvas 和 Scrollbar
    canvas = tk.Canvas(root)
    scrollbar = ttk.Scrollbar(root, orient="vertical", command=canvas.yview)
    canvas.configure(yscrollcommand=scrollbar.set)

    # 将 Scrollbar 放置在右侧
    scrollbar.pack(side="right", fill="y")
    canvas.pack(side="left", fill="both", expand=True)

    # 创建一个 Frame 放在 Canvas 上
    frame = tk.Frame(canvas)
    canvas.create_window((0, 0), window=frame, anchor="nw")

    # 更新 Canvas 的滚动区域
    frame.bind("<Configure>", lambda event: canvas.configure(scrollregion=canvas.bbox("all")))

    # 创建复选框
    checkboxes = []
    for i, text in enumerate(datas):
        checkbox = tk.Checkbutton(frame, text=text[:-4], variable=vars[i])
        checkbox.pack(anchor='w')  # 左对齐
        checkboxes.append(checkbox)

    # 创建全选按钮
    select_all_button = tk.Button(root, text="全选", command=toggle_all_checkboxes)
    select_all_button.pack()

    re_choose_file_button = tk.Button(root, text="重新选择文件", command=re_choose)
    re_choose_file_button.pack()

    # 创建按钮
    button = tk.Button(root, text="确认并开始输出", command=print_checkbox_status)
    button.pack()


# 创建主窗口并隐藏
root = tk.Tk()
root.title("选择要导出的文件")
root.withdraw()  # 隐藏主窗口
root.iconbitmap('Logo.ico')  # 设置主窗口图标

select_json_file_and_decode()

# 运行主循环
root.mainloop()
